/**
 * @brief Rational重载运算符版本
 * @author redfrogotr
 * @date 2022/3/26
 */
#include <iostream>

using namespace std;

class Rational 
{
private:
    int num;    // 分子
    int deno;   // 分母 > 0
    double value;   // 实数值

public:
    Rational() : num(0), deno(1), value(0) {}
    Rational(int num, int deno);
    void setNum(int num);   // 设置分子
    bool setDeno(int deno); // 设置分母
    void simple();          // 约分
    void print();
    Rational operator-() const;
    double operator-(const double d) const;
    Rational operator-(const Rational &r) const;
    Rational operator*(const Rational &r) const;
    bool operator<(const Rational &r) const;
    bool operator>(const Rational &r) const { return r < *this; }

    friend double operator-(const double, const Rational&);
};

Rational::Rational(int num, int deno) {
    this->num = num;
    if (deno == 0) {
        cout << "[WARN] Denominator in args cannot be ZERO, so 1 the default value is used!\n";
        this->deno = 1;
    } else if (deno > 0) {
        this->deno = deno;
    } else {
        // 保证分母大于0
        this->deno = -deno;
        this->num = -num;
    }
    this->simple();
    this->value = (double)this->num / this->deno;
}

void Rational::setNum(int num) {
    this->num = num;
    this->simple();
    this->value = (double)this->num / this->deno;
}

bool Rational::setDeno(int deno) {
    if (deno == 0) {
        return false;
    } else if (deno > 0) {
        this->deno = deno;
    } else {
        this->deno = -deno;
        this->num = -(this->num);
    }
    this->simple();
    this->value = (double)this->num / this->deno;
    return true;
}

void Rational::simple() {
    // 分子为0，不必约分
    if (num == 0) {
        return ;
    }
    // gcd
    int a = abs(num), b = abs(deno), r;
    do {
        r = a % b;
        a = b;
        b = r;
    } while (r != 0);
    
    num /= a;
    deno /= a;
}

void Rational::print() {
    cout << this << ':';
    if (num == 0) {
        cout << 0 << endl;
        return ;
    }
    if (deno == 1) {
        cout << num << endl;
    } else {
        cout << num << '/' << deno << endl;
    }
}

Rational Rational::operator-() const { 
    return Rational(-num, deno); 
}

double operator-(const double d, const Rational &r) {
    return d - r.value;
}

double Rational::operator-(const double d) const { 
    return value - d; 
}

Rational Rational::operator-(const Rational &r) const {
    return Rational(num * r.deno - r.num * deno, deno * r.deno);
}

Rational Rational::operator*(const Rational &r) const {
    return Rational(num * r.num, deno * r.deno);
}

bool Rational::operator<(const Rational &r) const {
    return num * r.deno < r.num * deno;
}

int main() {
    int num, deno;
    double d;
    // input 1st rational, inilializing by setter
    cout << "YOU can input NUMerator and DENOminator of Rational: " << endl;
    cin >> num >> deno;
    Rational r1(num, deno);
    r1.print();
    // input 2nd rational, initializing by constructor
    cout << "YOU can input NUMerator and DENOminator of 2nd Rational: " << endl;
    cin >> num >> deno;
    Rational r2(num, deno);
    r2.print();
    // input a double
    cout << "YOU can input a double: " << endl;
    cin >> d;

    cout << "-r1: ";
    (-r1).print();
    cout << "r1 - d: ";
    cout << r1 - d << endl;
    cout << "d - r1: ";
    cout << d - r1 << endl;
    cout << "r1 - r2: ";
    (r1 - r2).print();
    cout << "r1 * r2: ";
    (r1 * r2).print();
    cout << "r1 > r2: " << (r1 > r2) << endl;
    cout << "r1 < r2: " << (r1 < r2) << endl;

    return 0;
}
